////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//         This file is distributed under the BSD 2-Clause open source license. See Licenses/License.txt for details.         //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_FUNCTION_TEMPLATES_INL___
#define __WN_FUNCTION_TEMPLATES_INL___

namespace WNScripting {
    template<typename R> 
    eWNTypeError WNScriptingEngine::GetPointerToFunction(const WN_CHAR* _file, const WN_CHAR* _functionName, R (*&_outPtr)() ) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
        std::vector<WNScriptType> params;
        void* ptr = NULL;
        eWNTypeError err;
        if(eWNOK != (err = GetFunctionPointer(_file, _functionName, t, params, ptr))){
            return(err);
        }
        _outPtr = reinterpret_cast<R(*)()>(ptr);
        return(eWNOK);
    }

    template<typename R, typename T1> 
    eWNTypeError WNScriptingEngine::GetPointerToFunction(const WN_CHAR* _file, const WN_CHAR* _functionName, R (*&_outPtr)(T1) ) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
    
        std::vector<WNScriptType> params;
        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        void* ptr = NULL;   
        eWNTypeError err;
        if(eWNOK != (err = GetFunctionPointer(_file, _functionName, t, params, ptr))){
            return(err);
        }
        _outPtr = reinterpret_cast<R(*)(T1)>(ptr);
        return(eWNOK);
    }

    template<typename R, typename T1, typename T2> 
    eWNTypeError WNScriptingEngine::GetPointerToFunction(const WN_CHAR* _file, const WN_CHAR* _functionName, R (*&_outPtr)(T1, T2) ) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
    
        std::vector<WNScriptType> params;
        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T2>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        
        void* ptr = NULL;
        eWNTypeError err;
        if(eWNOK != (err = GetFunctionPointer(_file, _functionName, t, params, ptr))){
            return(err);
        }
        _outPtr = reinterpret_cast<R(*)(T1, T2)>(ptr);
        return(eWNOK);
    }

    template<typename R, typename T1, typename T2, typename T3> 
    eWNTypeError WNScriptingEngine::GetPointerToFunction(const WN_CHAR* _file, const WN_CHAR* _functionName, R (*&_outPtr)(T1, T2, T3) ) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
    
        std::vector<WNScriptType> params;
        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T2>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T3>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        void* ptr = NULL;
        eWNTypeError err;
        if(eWNOK != (err = GetFunctionPointer(_file, _functionName, t, params, ptr))){
            return(err);
        }
        _outPtr = reinterpret_cast<R(*)(T1, T2, T3)>(ptr);
        return(eWNOK);
    }

    template<typename R, typename T1, typename T2, typename T3, typename T4> 
    eWNTypeError WNScriptingEngine::GetPointerToFunction(const WN_CHAR* _file, const WN_CHAR* _functionName, R (*&_outPtr)(T1, T2, T3, T4) ) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
    
        std::vector<WNScriptType> params;
        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T2>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T3>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T4>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        void* ptr = NULL;
        eWNTypeError err;
        if(eWNOK != (err = GetFunctionPointer(_file, _functionName, t, params, ptr))){
            return(err);
        }
        _outPtr = reinterpret_cast<R(*)(T1, T2, T3, T4)>(ptr);
        return(eWNOK);
    }
    
    template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5> 
    eWNTypeError WNScriptingEngine::GetPointerToFunction(const WN_CHAR* _file, const WN_CHAR* _functionName, R (*&_outPtr)(T1, T2, T3, T4, T5) ) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
    
        std::vector<WNScriptType> params;
        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T2>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T3>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T4>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T5>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        void* ptr = NULL;
        eWNTypeError err;
        if(eWNOK != (err = GetFunctionPointer(_file, _functionName, t, params, ptr))){
            return(err);
        }
        _outPtr = reinterpret_cast<R(*)(T1, T2, T3, T4, T5)>(ptr);
        return(eWNOK);
    }

    template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> 
    eWNTypeError WNScriptingEngine::GetPointerToFunction(const WN_CHAR* _file, const WN_CHAR* _functionName, R (*&_outPtr)(T1, T2, T3, T4, T5, T6) ) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
    
        std::vector<WNScriptType> params;
        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T2>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T3>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T4>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T5>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        params.push_back(GetTypeByName(TypeMapping<T6>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        void* ptr = NULL;
        eWNTypeError err;
        if(eWNOK != (err = GetFunctionPointer(_file, _functionName, t, params, ptr))){
            return(err);
        }
        _outPtr = reinterpret_cast<R(*)(T1, T2, T3, T4, T5, T6)>(ptr);
        return(eWNOK);
    }

    template<typename R> 
    eWNTypeError WNScriptingEngine::RegisterCFunction(const WN_CHAR* _name, R (*_ptr)()) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
        std::vector<WNScriptType> params;
        
        eWNTypeError err;
        if(eWNOK != (err = RegisterFunction(_name, t, params, reinterpret_cast<void*>(_ptr)))){
            return(err);
        }
        return(eWNOK);
    }

    template<typename R, typename T1> 
    eWNTypeError WNScriptingEngine::RegisterCFunction(const WN_CHAR* _name, R (*_ptr)(T1)) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
        std::vector<WNScriptType> params;

        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        
        eWNTypeError err;
        if(eWNOK != (err = RegisterFunction(_name, t, params, reinterpret_cast<void*>(_ptr)))){
            return(err);
        }
        return(eWNOK);
    }

    template<typename R, typename T1, typename T2> 
    eWNTypeError WNScriptingEngine::RegisterCFunction(const WN_CHAR* _name, R (*_ptr)(T1, T2)) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
        std::vector<WNScriptType> params;

        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        
        params.push_back(GetTypeByName(TypeMapping<T2>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        eWNTypeError err;
        if(eWNOK != (err = RegisterFunction(_name, t, params, reinterpret_cast<void*>(_ptr)))){
            return(err);
        }
        return(eWNOK);
    }

    template<typename R, typename T1, typename T2, typename T3> 
    eWNTypeError WNScriptingEngine::RegisterCFunction(const WN_CHAR* _name, R (*_ptr)(T1, T2, T3)) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
        std::vector<WNScriptType> params;

        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        
        params.push_back(GetTypeByName(TypeMapping<T2>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        params.push_back(GetTypeByName(TypeMapping<T3>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        eWNTypeError err;
        if(eWNOK != (err = RegisterFunction(_name, t, params, reinterpret_cast<void*>(_ptr)))){
            return(err);
        }
        return(eWNOK);
    }

    template<typename R, typename T1, typename T2, typename T3, typename T4> 
    eWNTypeError WNScriptingEngine::RegisterCFunction(const WN_CHAR* _name, R (*_ptr)(T1, T2, T3, T4)) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
        std::vector<WNScriptType> params;

        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        
        params.push_back(GetTypeByName(TypeMapping<T2>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        params.push_back(GetTypeByName(TypeMapping<T3>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        params.push_back(GetTypeByName(TypeMapping<T4>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        eWNTypeError err;
        if(eWNOK != (err = RegisterFunction(_name, t, params, reinterpret_cast<void*>(_ptr)))){
            return(err);
        }
        return(eWNOK);
    }

    template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5> 
    eWNTypeError WNScriptingEngine::RegisterCFunction(const WN_CHAR* _name, R (*_ptr)(T1, T2, T3, T4, T5)) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
        std::vector<WNScriptType> params;

        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        
        params.push_back(GetTypeByName(TypeMapping<T2>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        params.push_back(GetTypeByName(TypeMapping<T3>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        params.push_back(GetTypeByName(TypeMapping<T4>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        params.push_back(GetTypeByName(TypeMapping<T5>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        eWNTypeError err;
        if(eWNOK != (err = RegisterFunction(_name, t, params, reinterpret_cast<void*>(_ptr)))){
            return(err);
        }
        return(eWNOK);
    }

    template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> 
    eWNTypeError WNScriptingEngine::RegisterCFunction(const WN_CHAR* _name, R (*_ptr)(T1, T2, T3, T4, T5, T6)) {
        WNScriptType t = GetTypeByName(TypeMapping<R>::GetTypeName());
        if(!t) {
            return(eWNBadType);
        }
        std::vector<WNScriptType> params;

        params.push_back(GetTypeByName(TypeMapping<T1>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }
        
        params.push_back(GetTypeByName(TypeMapping<T2>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        params.push_back(GetTypeByName(TypeMapping<T3>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        params.push_back(GetTypeByName(TypeMapping<T4>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        params.push_back(GetTypeByName(TypeMapping<T5>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        params.push_back(GetTypeByName(TypeMapping<T6>::GetTypeName()));
        if(!params.back()) {
            return(eWNBadType);
        }

        eWNTypeError err;
        if(eWNOK != (err = RegisterFunction(_name, t, params, reinterpret_cast<void*>(_ptr)))){
            return(err);
        }
        return(eWNOK);
    }
}
#endif
